<template>
  <div class="containers" ref="content" :style="{height: panelHeight}">
    <div class="loading" v-if="loading">
        Loading...
    </div>
    <template v-else>
        <div class="canvas" ref="canvas">
        </div>
        <button ref="saveBpmn" class="save_xml" :disabled="saveXmlInfo.type" @click="saveBpmnUpdate">修改</button>
        <div id="js-properties-panel" class="panel"></div>
    </template>
  </div>
</template>

<script>
import BpmnModeler from 'bpmn-js/lib/Modeler'
import propertiesPanelModule from '../../workflow/properties-panel'
import propertiesProviderModule from '../../workflow/properties-panel/provider/activiti'
import customTranslate from '../../workflow/customTranslate/customTranslate'
import customControlsModule from '../../workflow/customControls'
import activitiModdleDescriptor from '../../mock/activiti.json'
import { xmlStr } from '../../mock/xmlStr'
import {mapState, mapMutations, mapActions} from 'vuex'
import {removeStore} from '../../utils/storage'

export default {
  name: '',
  components: {},
  created() {
    this.getUserInfo();
  },
  mounted(){
    this.init();
  },
  data() {
    return {
        // bpmn建模器
        bpmnModeler: null,
        container: null,
        canvas: null,
        loading: true,
        xmlUrl: '',
        defaultXmlStr:xmlStr,
        xmlRes: '',
        saveXmlInfo: {
            type: true,
            xml: ''
        },
        processInfo: {},
    }
  },
// 方法集合
  methods: {
    ...mapActions(['getUserInfo']),
    async init () {
      // 在初始化时先加载loading
      this.loading = true;
      // 根据路由传来的id获取模型
      const modelRes = await this.$api.flowChartService.getBpmnInfo(this.$route.query.moduleId);
      // 请求后loading关闭
      this.loading = false;
      this.xmlRes = modelRes || '';
      // 获取模型信息 key name
      const modelInfo = await this.$api.flowChartService.getModalInfo(this.$route.query.moduleId);
      this.processInfo = modelInfo.data;
      this.$nextTick(()=>{ 
        this.initBpmn();
      })
    },
    initBpmn(){
      // 这里是初始化工作流的代码
      let customTranslateModule = {
        translate: [ 'value', customTranslate]
      };
      // 获取到属性ref为“content”的dom节点
      this.container = this.$refs.content
      // 获取到属性ref为“canvas”的dom节点
      const canvas = this.$refs.canvas
      // 建模
      this.bpmnModeler = new BpmnModeler({
        // 添加控制板
        container: canvas,
        propertiesPanel: {
          parent: '#js-properties-panel'
        },
        additionalModules: [
          // 左边工具栏以及节点
          propertiesProviderModule,
          // 右边的工具栏
          propertiesPanelModule,
          // 汉化
          customTranslateModule,
          customControlsModule
        ],
        moddleExtensions: {
          activiti: activitiModdleDescriptor
        }
      })
      //模块拓展，拓展activiti的描述
      this.createNewDiagram()
    },
    async createNewDiagram () {
        const that = this;
        let bpmnXmlStr = '';
        // 判断通过请求获取的xml是否有，如果没有就加载默认的xml
        if(this.xmlRes === ''){ 
          bpmnXmlStr = this.defaultXmlStr;
        }else{
          bpmnXmlStr = this.xmlRes;
        }
        this.transformCanvas(bpmnXmlStr);
    },
    transformCanvas(bpmnXmlStr){
      // 将字符串转换成图显示出来
      this.bpmnModeler.importXML(bpmnXmlStr, (err) => {
        if (err) {
            console.error(err)
        }
        else {
            this.success()
            this.getProcessModel();
            this.setProcess();
        }
        // 让图能自适应屏幕
        var canvas = this.bpmnModeler.get('canvas');
        canvas.zoom('fit-viewport')
      })
    },
    setProcess(){
      // 将process的属性 id name变为disabled状态
      document.getElementById('activiti-id').setAttribute("disabled", "disabled");
      document.getElementById('activiti-name').removeAttribute("contenteditable");
      document.getElementById('activiti-name').style.cssText="background :#f6f6f6; border:1px solid #ccc;";
    },
    getProcessModel(){
      // 获取画布
      const canvas = this.bpmnModeler.get('canvas');
      const modeling = this.bpmnModeler.get('modeling');
      let node = canvas._elementRegistry._elements;
      let shape = {};
      for(let key in node){
        // 遍历画布中的节点元素，如果是process的话，就将元素赋值给shape
        if(node[key].element.type === 'bpmn:Process'){
          shape = node[key].element;
        }
      }
      // 修改process的name和id为模型的key name 
      modeling.updateProperties(shape, {
        name: this.processInfo.name,
        id: this.processInfo.key
      });
    },
    success() {
      this.addEventBusListener();
      this.addModelerListener();
    },
    setUserTask(shape){
      let taskInfo = {
          userOptions: shape.businessObject.candidateUsers || [],
          rolaOptions: shape.businessObject.candidateGroups || []
      }
      const modeling = this.bpmnModeler.get('modeling');
      handleAddFunClick('activiti-candidateUsersSelect-select', taskInfo.userOptions, 'candidateUsers')
      handleAddFunClick('activiti-candidateGroupsSelect-select', taskInfo.rolaOptions, 'candidateGroups')
      function handleAddFunClick(id, data, type){
        if(document.getElementById(id)){
          document.getElementById(id).addEventListener('change',function(){
              const val = data.indexOf(this.options[this.selectedIndex].value);
              if(val == -1){
                  data.push(this.options[this.selectedIndex].value);
                  if(type === 'candidateUsers'){
                      modeling.updateProperties(shape, {
                          candidateUsers: data
                      })
                  }else if(type === 'candidateGroups'){
                      modeling.updateProperties(shape, {
                          candidateGroups: data
                      })
                  }
              }
          })
        }
      }
    },
    addModelerListener() {
        const bpmnjs = this.bpmnModeler;
        const that = this;
        var elementRegistry = bpmnjs.get('elementRegistry');
        const modeling = bpmnjs.get('modeling');
        const eventTypes = ['create.cleanup', 'element.click'];
        eventTypes.forEach(item=>{
            this.bpmnModeler.on(item, e => {
                var shape = e.element ? elementRegistry.get(e.element.id) : e.shape;
                if (shape.type === 'bpmn:UserTask') {
                  this.setUserTask(shape);
                }
                if (shape.type === 'bpmn:Process') {
                  this.setProcess();
                }
            })
        })
    },
    addEventBusListener() {
      const that = this;
      const eventBus = this.bpmnModeler.get('eventBus');
      this.bpmnModeler.on('commandStack.changed', function (e) {
        that.saveDiagram(function (err, xml) {
          that.saveXmlInfo.type = false;
          that.saveXmlInfo.xml = err ? null : xml;
        })
      })
    },
    saveDiagram(done){
      this.bpmnModeler.saveXML({format: true},function(err,xml){
        done(err,xml);
      })
    },
    async saveBpmnUpdate(){
      const { xml } = this.saveXmlInfo;
      let xmlFile = new File([xml], 'diagram.bpmn');
      let xmlFormData = new FormData();
      xmlFormData.append('file', xmlFile);
      xmlFormData.append('id', this.$route.query.moduleId);
      try {
        await this.$api.flowChartService.updataModule(xmlFormData).then(res=>{
            if(res.returnCode === 0){
              this.$message.success('修改成功');       
            }else{
              this.$message.error(res.returnMessage);       
            }
        })
      } catch (error) {
        this.$message.error(error);       
      }
    }
  },
// 计算属性
  computed: {
    ...mapState(['getHost',  'panelHeight'])
  },
  destroyed () {
    removeStore('getUserInfo')
  }
}
</script>

<style scoped>
.containers{
	background-color: #ffffff;
	width: 100%;
  position: relative;
}
.canvas{
	width: 100%;
	height: 100%;
}
.panel{
	position: absolute;
	right: 0;
	top: 0;
  width: 300px;
  height: 100%;
  overflow: scroll;
}
.loading{
  font-size: 30px;
  margin: 100px 0;
}
.save_xml{
    float: left;
    margin: 10px 0 0 20px;
    width: 94px;
    padding: 8px 5px;
    background: #fafafa;
    border: 1px solid #ccc;
    color: #000;
    position: absolute;
    bottom: 10px;
    left: 0;  
}
.save_xml:disabled{
    background: #fff;
    color: #ccc;
    border: 1px solid #ddd;
}
</style>